<?php
/**
 *
 * 보안 관련 class
 * 보안관련 필터링 기능을 합니다.
 *
 *
 */

class utilFilterSecure
{
    private $className = '';
    private $action = '';
    private $params = array();
    private $enableFilter = false;
    public static $aDebugMsg = array();

    function __construct($className, $action, $params)
    {
        $this->className = $className;
        $this->action = $action;
        $this->params = $params;
    }

    public static function filterSecure($className, $action, $params)
    {
        $utilFilterSecure = new utilFilterSecure($className, $action, $params);
        return $utilFilterSecure->execute();
    }

    public function execute()
    {
        // 필요없는 파라미터 제거
        $this->ignoreParamsUnset();
        
        // 데이터 획득
        $aFilterParam = $this->getIniFileData();
        $aFilterParam = $this->getCommonParam($aFilterParam);


        if ($this->enalbeFilter) {
            $this->setMessage('PARAMETER FILTER RUN START!');
            $aReturnParam = $this->getValidParam($aFilterParam);

            $diffParamKey = array_diff(array_keys($this->params), array_keys($aReturnParam));
            $this->setMessage(implode(',', $diffParamKey).' 파라메터가 필터링 되어 제외되었습니다.');

        } else {
            $this->setMessage('파라메터 필터기능이 작동하지 않습니다.');
            $aReturnParam = $this->params;
        }

        return $aReturnParam;
    }

    /**
     *
     * 필요없는 파라미터 제거
     */
    private function ignoreParamsUnset()
    {
        $_params = array();

        $aIgnoreParam = explode(',', SC_IGNORE_PARAM);
        foreach ($this->params as $k => $v) {
            if (in_array($k, $aIgnoreParam)) {
                continue;
            }
            $_params[$k] = $v;
        }
        $this->params = $_params;
    }

    /**
     *
     * 공통, 자신의 url 에 정의된 데이터만 가져온다.
     * 기본 환경설정 데이터를 array 로 리턴 받는다.
     */
    private function getIniFileData()
    {
        preg_match_all('/([^A-Z]|[^a-z0-9])([a-z0-9]+)/', $this->className, $aClassName);
        $aClassName = array_slice(array_slice($aClassName[0], 0, -1), 1);
        $iniFile = SC_DIR_RESOURCE.'/params/'.implode('/', $aClassName).'/'.implode('', $aClassName).'.ini';
        $this->setMessage('필터링 파일 :: '.$iniFile);
        if (!file_exists($iniFile)) return null;

        $utilIni = new utilIni($iniFile);
        $aParam = $utilIni->toArray();
        $actionParam = $aParam[$this->action];
        $this->enableFilter = (is_array($actionParam)) ? true : false;

        return $aParam['common'] ? array_merge($aParam['common'], $actionParam) : $actionParam;
    }

    /**
     *
     * 공통 파라미터 세팅
     * @param array $aFilterParam
     */
    private function getCommonParam($aFilterParam)
    {
        $aFilterParam['url'] = 'type=string&length=30';
        $aFilterParam['secure'] = 'type=string&length=10';

        return $aFilterParam;
    }

    private function getValidParam($aFilterParam)
    {
        $aValidParams = array();
        $aPatten = $this->getParamPatten($aFilterParam);
        $aParamKey = array_keys($aPatten);

        foreach ($this->params as $key => $value) {
            $pattenKey = $this->isAgreeKey($key, $aParamKey, $aPatten);
            if (empty($pattenKey) === true) continue;

            parse_str($aFilterParam[$pattenKey], $aParamOption);
            $this->setMessage('['.$key.'] 가 데이터형 : '.$aParamOption['type'].', 문자열길이 : '.$aParamOption['length'].' 로 조건으로 필터링 됩니다.');
            $aValidParams[$key] = $this->lengthCheck($value, $aParamOption);
            $aValidParams[$key] = $this->conversionParam($aValidParams[$key], $aParamOption);
        }

        return $aValidParams;
    }

    private function conversionParam($data, $aOption)
    {
        if ($aOption['type'] == 'array') {
            $aData = array();
            foreach ($data as $k => $v) {
                $aData[$k] = $this->_conversionParam($v, $aOption['arrayData']);
            }

            return $aData;

        } else {
            return $this->_conversionParam($data, $aOption['type']);
        }
    }

    private function _conversionParam($value, $type)
    {
        switch ($type) {
            case 'int' : return intval($value); break;
            case 'string' : return strval($value); break;
            case 'float' : return floatval($value); break;
        }
    }

    /**
     *
     * 키 패턴 조회
     * @param array $aFilterParam
     * @return array $aPatten
     */
    private function getParamPatten($aFilterParam)
    {
        $aPatten = array();
        foreach ($aFilterParam as $k => $v) {
            $aParamOption = $this->getParseOption($aFilterParam[$k]);
            if (empty($aParamOption['keyPatten']) === true) continue;
            $aPatten[$k] = $aParamOption['keyPattne'];
        }
        return $aPatten;
    }

    private function isAgreeKey($key, $aParamkey, $aPatten)
    {
        if (in_array($key, $aParamkey)) return $key;
        if (empty($aPatten) === true) return false;

        foreach ($aPatten as $key => $patten) {
            preg_match_all("/$patten/", $key, $aMatches);
            if ($aMatchesf[0][0]) return $k;
        }

        return false;
    }

    /**
     *
     * 옵션 조회
     * @param string $sOption
     * @return array $aOption
     */
    private function getParseOption($sOption)
    {
        if (empty($sOption) === true) return;

        $_aOption = explode('&', $sOption);
        foreach ($_aOption as $key => $option) {
            list ($k, $v) = explode('=', $option);
            $aOption[$k] = $v;
        }
        return $aOption;
    }

    private function lengthCheck($data, $aOption)
    {
        if ($aOption['type'] == 'array') {
            $aData = array();
            foreach ($data as $k => $v) {
                $aData[$k] = $this->_lengthCheck($v, $aOption['length']);
            }

            return $aData;

        } else {
            return $this->_lengthCheck($data, $aOption['length']);

        }
    }

    private function _lengthCheck($sString, $sLength)
    {
        if ($sLength == 'ALL') return $sString;
        if (empty($sLength) === true) return $sString;

        return (strlen($sString) >= $sLength) ? substr($sString, 0, $sLength) : $sString;
    }

    private function setMessage($msg)
    {
        if (!DEBUG) return;

        self::$aDebugMsg[] = $msg;
    }
}